﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using MathNet.Symbolics;
using Expr = MathNet.Symbolics.SymbolicExpression;

namespace NumericalAnalysis.DataInterpolation.MathNetExample
{
    internal class SymbolicDefine
    {
        public static void SymbolicDemo()
        {
            var x = Expr.Variable("x");
            var y = Expr.Variable("y");
            var a = Expr.Variable("a");
            var b = Expr.Variable("b");
            var c = Expr.Variable("c");
            var d = Expr.Variable("d");


            string str = (a + a).ToString();


            Console.WriteLine(str);




            var sdf = a + a;

            (a + a).ToString();           // returns string "2*a"
            (a * a).ToString();           // returns string "a^2"
            (2 + 1 / x - 1).ToString();   // returns string "1 + 1/x"
            ((a / b / (c * a)) * (c * d / a) / d).ToString();   // returns string "1/(a*b)"

            (1 / (a * b)).ToString();      // returns string "1/(a*b)"
                                           //(1 / (a * b)).ToInternalString();  // returns string "a^(-1)*b^(-1)"
            (1 / (a * b)).ToLaTeX();       // returns string "\frac{1}{ab}"

            //Expr.Parse("1/(a*b");  // throws an exception
            Expr.Parse("1/(a*b)").ToString(); // Returns string "1/(a*b)"

            var symbols = new Dictionary<string, FloatingPoint>
               {{ "a", 2.0 },
                { "b", 3.0 }};

            // Returns 0.166666666666667
            var cc = (1 / (a * b)).Evaluate(symbols).RealValue;


            // Compilation to a function
            Func<double, double, double> f = (1 / (a * b)).Compile("a", "b");
            f(2.0, 3.0);// returns 0.166666666666667

            // Returns string "3/8 + cos(2*x)/2 + cos(4*x)/8"
            x.Cos().Pow(4).TrigonometricContract().ToString();

            // Taylor Expansion
            Expr Taylor(int k, Expr symbol, Expr al, Expr xl)
            {
                int factorial = 1;
                Expr accumulator = Expr.Zero;
                Expr derivative = xl;
                for (int i = 0; i < k; i++)
                {
                    var subs = derivative.Substitute(symbol, al);
                    derivative = derivative.Differentiate(symbol);
                    accumulator = accumulator + subs / factorial * ((symbol - al).Pow(i));
                    factorial *= (i + 1);
                }
                return accumulator.Expand();
            }

            // Returns string "1 + x - x^2/2 - x^3/6"
            Taylor(4, x, 0, x.Sin() + x.Cos()).ToString();

            Console.WriteLine(Taylor(1, x, 5, x.Sin()).ToString());

        }
    }
}
